package main

import (
	"doubanApp/logger"
	"doubanApp/pie"
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"golang.org/x/net/html"
	"io"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"unicode"
)

// 从URL中提取书籍ID
func extractBookID(url string) string {
	// 多种可能的模式
	patterns := []string{
		`/book/(\d+)`,            // 标准格式: /book/数字
		`/subject/(\d+)`,         // 另一种常见格式
		`dispatch/(\d+)`,         // 示例中出现的格式
		`/(\d+)\?`,               // 在查询参数前的数字
		`[^0-9](\d{5,12})[^0-9]`, // 通用长数字匹配
	}

	for _, pattern := range patterns {
		re := regexp.MustCompile(pattern)
		matches := re.FindStringSubmatch(url)

		if len(matches) > 1 {
			return matches[1]
		}
	}
	return ""
}

// 获取网页HTML内容
func fetchHTML(url string) (string, error) {
	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return "", err
	}

	// 设置User-Agent模拟浏览器
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")

	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("HTTP请求失败: %s", resp.Status)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	return string(body), nil
}

// 解析书籍基本信息 - 最终修复版
func parseBookInfo(html string, bookId string) (BookInfo, error) {
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
	if err != nil {
		return BookInfo{}, err
	}

	info := BookInfo{}
	info.OrgId = bookId
	// 提取书名
	info.Title = doc.Find("h1 span").First().Text()

	src := doc.Find("#mainpic a").AttrOr("href", "")
	info.Cover = src

	// 提取基本信息区域
	infoDiv := doc.Find("#info")
	if infoDiv.Length() == 0 {
		return info, fmt.Errorf("未找到书籍信息区域")
	}

	// 遍历所有包含class="pl"的元素
	infoDiv.Find("span.pl").Each(func(i int, s *goquery.Selection) {
		field := strings.TrimSpace(strings.TrimSuffix(s.Text(), ":"))

		// 特殊处理作者和译者字段
		if field == "作者" || field == "译者" {
			// 获取父元素
			parent := s.Parent()

			// 提取所有链接文本
			var values []string
			parent.Find("a").Each(func(i int, a *goquery.Selection) {
				values = append(values, strings.TrimSpace(a.Text()))
			})

			if len(values) > 0 {
				if field == "作者" {
					info.Author = values[0]
				} else if field == "译者" {
					info.Translators = values
				}
			}
			return
		}

		// 对于其他字段，提取紧邻的文本内容
		value := extractAdjacentText(s)

		// 根据字段名存储值
		switch field {
		case "出版社":
			// 出版社可能是链接或纯文本
			if next := s.Next(); next.Is("a") {
				info.Publisher = strings.TrimSpace(next.Text())
			} else {
				info.Publisher = value
			}
		case "副标题":
			info.Subtitle = value
		case "原作名":
			info.Original = value
		case "出版年":
			info.PubYear = value
		case "页数":
			// 尝试解析页数
			if pages, err := strconv.Atoi(strings.TrimSuffix(value, "页")); err == nil {
				info.Pages = pages
			} else if pages, err := strconv.Atoi(value); err == nil {
				info.Pages = pages
			}
		case "定价":
			info.Price = value
		case "装帧":
			info.Binding = value
		case "丛书":
			// 丛书可能是链接或纯文本
			if next := s.Next(); next.Is("a") {
				info.Series = strings.TrimSpace(next.Text())
			} else {
				info.Series = value
			}
		case "ISBN":
			info.ISBN = value
		}
	})

	// 提取简介
	intro := doc.Find("div.intro")
	if intro.Length() > 0 {
		// 合并所有段落
		intro.Find("p").Each(func(i int, s *goquery.Selection) {
			if i > 0 {
				info.Intro += "\n\n"
			}
			info.Intro += strings.TrimSpace(s.Text())
		})
	}

	return info, nil
}

// 提取紧邻的文本内容（非标签内容）
func extractAdjacentText(s *goquery.Selection) string {
	// 获取底层的HTML节点
	node := s.Nodes[0]

	// 查找下一个兄弟节点
	next := node.NextSibling
	for next != nil {
		// 如果是文本节点
		if next.Type == html.TextNode {
			text := strings.TrimSpace(next.Data)
			if text != "" {
				return text
			}
		}
		next = next.NextSibling
	}

	// 如果没找到文本节点，尝试从父节点提取
	parentText := s.Parent().Text()
	fieldText := s.Text()
	if idx := strings.Index(parentText, fieldText); idx != -1 {
		value := strings.TrimSpace(parentText[idx+len(fieldText):])
		return strings.TrimPrefix(value, ":")
	}

	return ""
}

// 清洗目录信息
func clearTocInfo(tocInfo string) (string, error) {
	var tocObject []Chapter
	err := json.Unmarshal([]byte(tocInfo), &tocObject)
	if err != nil {
		return "", err
	}
	var tocInfoStr string
	tmpLenth := len(tocObject)
	if len(tocObject) > 0 {

		for i, chapter := range tocObject {
			if (i + 1) == tmpLenth {
				tocInfoStr += string(chapter.Title)
			} else {
				tocInfoStr += string(chapter.Title) + "||"
			}
		}

		return tocInfoStr, nil
	}
	return "", nil
}

// 解析目录信息
func parseTOC(html, bookID string) ([]Chapter, error) {
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
	if err != nil {
		return nil, err
	}

	// 定位目录元素
	tocDiv := doc.Find(fmt.Sprintf("#dir_%s_full", bookID))
	if tocDiv.Length() == 0 {
		return nil, fmt.Errorf("未找到目录元素")
	}

	var chapters []Chapter

	// 处理每个文本节点
	tocDiv.Contents().Each(func(i int, s *goquery.Selection) {
		if s.Is("br") {
			return
		}

		text := s.Text()
		if strings.TrimSpace(text) == "" || strings.TrimSpace(text) == ")" {
			return
		}

		// 跳过"收起"链接和非目录行
		if strings.Contains(text, "收起") || strings.Contains(text, "· · · · · ·") {
			return
		}

		// 提取页码和标题
		title, page := extractTitleAndPage(text)
		if title != "" {
			chapters = append(chapters, Chapter{Title: title, Page: page})
		}
	})

	return chapters, nil
}

// 从文本行提取标题和页码
func extractTitleAndPage(line string) (string, int) {
	// 移除所有HTML标签
	cleanLine := regexp.MustCompile(`<[^>]+>`).ReplaceAllString(line, "")
	cleanLine = strings.TrimSpace(cleanLine)

	// 查找最后一个数字序列作为页码
	lastDigitIndex := -1
	for i := len(cleanLine) - 1; i >= 0; i-- {
		if unicode.IsDigit(rune(cleanLine[i])) {
			lastDigitIndex = i
		} else if lastDigitIndex != -1 {
			break
		}
	}

	if lastDigitIndex == -1 {
		return cleanLine, 0 // 没有页码
	}

	// 确定页码起始位置
	pageStart := lastDigitIndex
	for pageStart > 0 && unicode.IsDigit(rune(cleanLine[pageStart-1])) {
		pageStart--
	}

	// 提取页码和标题
	pageStr := cleanLine[pageStart : lastDigitIndex+1]
	title := strings.TrimSpace(cleanLine[:pageStart])

	// 转换页码为整数
	page, _ := strconv.Atoi(pageStr)

	return title, page
}

// 保存为JSON文件
func saveAsJSON(logg logger.Logger, cache *pie.FileCache, data interface{}, filename string) error {
	file, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return err
	}

	if err := cache.Set(filename, file); err != nil {
		return err
	}

	//return os.WriteFile(filename, file, 0644)
	return nil
}
